//
//  SocketManager.m
//  Demo
//
//  Created by xiu on 2020/4/22.
//  Copyright © 2020 111. All rights reserved.
//

#import "SocketManager.h"
#import <arpa/inet.h>
#import "JXHttpRequest.h"
#import "TokenGenerator.h"

@interface SocketManager  ()<SRWebSocketDelegate>
@property (nonatomic, strong) NSTimer  *heartBeatTimer;  //心跳定时器
@property (nonatomic, strong) NSTimer  *netWorkTestingTimer;  //没有网络的时候检测网络定时器
@property (nonatomic, assign) NSTimeInterval  reConnectTime;  //重连时间
@property (nonatomic, strong) NSMutableArray  *sendDataArray;  //存储要发送给服务端的数据
//用于判断是否主动关闭长连接，如果是主动断开连接，连接失败的代理中，就不用执行  重新连接方法
@property (nonatomic, assign) BOOL  isActivelyClose;
@property (nonatomic, strong) JXHttpRequest *bbsNet;
@property (nonatomic, strong) NSString *serverUrl;
@end

@implementation SocketManager

+(instancetype)shared{
    static  SocketManager  *_instance  =  nil;
    static  dispatch_once_t  onceToken;
    dispatch_once(&onceToken,  ^{
            _instance  =  [[self  alloc]init];
        });
    return  _instance;
}

- (instancetype)init
{
    self  =  [super  init];
    if (self) {
        self.reConnectTime  =  0;
        self.isActivelyClose  =  NO;
        self.sendDataArray  =  [[NSMutableArray  alloc]  init];
        self.bbsNet = [[JXHttpRequest alloc] init];
    }
    return  self;
}

//建立长连接
- (void)connectServer{
    self.isActivelyClose  =  NO;
    self.webSocket.delegate  =  nil;
    [self.webSocket  close];
    _webSocket  =  nil;
    
    // 获取连接地址
    if (JXRequestConfig.sharedManager.uid) {
        if (self.serverUrl.length) {
            long l = [[NSDate date] timeIntervalSince1970] / 1000 + 43200;
            NSString *key = JXRequestConfig.sharedManager.uid;
            NSString *content = [NSString stringWithFormat:@"%@#%@",@(l),key];
            NSString *url = [NSString  stringWithFormat:@"ws://%@/sub?key=%@&heartbeat=%@&uid=%@&ver=%@&role=1&token=%@",self.serverUrl,JXRequestConfig.sharedManager.uid,@(60),JXRequestConfig.sharedManager.uid,JXRequestConfig.sharedManager.appVer,[TokenGenerator neu_encryptAESData:content]];
            self.webSocket  =  [[SRWebSocket  alloc] initWithURL:[NSURL URLWithString:url]];
            self.webSocket.delegate  =  self;
            [self.webSocket  open];
        } else {
            weak_block_self;
            [self.bbsNet netSocketServerAndPort:[NSString stringWithFormat:@"%@",self.getserverAndPort] callback:^(BOOL isSuccess, id object) {
                if (isSuccess && [object objectForKey:@"data"]) {
                    weakSelf.serverUrl = [[object objectForKey:@"data"] objectForKey:@"server"];
                    long l = [[NSDate date] timeIntervalSince1970] / 1000 + 43200;
                    NSString *key = JXRequestConfig.sharedManager.uid;
                    NSString *content = [NSString stringWithFormat:@"%@#%@",@(l),key];
                    NSString *url = [NSString  stringWithFormat:@"ws://%@/sub?key=%@&heartbeat=%@&uid=%@&ver=%@&role=1&token=%@",weakSelf.serverUrl,JXRequestConfig.sharedManager.uid,@(60),JXRequestConfig.sharedManager.uid,JXRequestConfig.sharedManager.appVer,[TokenGenerator neu_encryptAESData:content]];
                    //[SVProgressHUD showSuccessWithStatus:serverUrl];
                    weakSelf.webSocket  =  [[SRWebSocket  alloc] initWithURL:[NSURL URLWithString:url]];
                    weakSelf.webSocket.delegate  =  self;
                    [weakSelf.webSocket  open];
                } else {
                    [weakSelf reConnectServer];
                }
            }];
        }
    }
}

#pragma  mark  --------------------------------------------------
#pragma  mark  -  socket  delegate
///开始连接
-(void)webSocketDidOpen:(SRWebSocket  *)webSocket{
    NetLog(@"socket  开始连接");
    self.reConnectTime = 0;
    self.isConnect  =  YES;
    self.connectType  =  WebSocketConnect;
    [self  initHeartBeat];// 开始心跳
    
    // [SVProgressHUD showSuccessWithStatus:@"长连接连接成功"];
}
///连接失败
-(void)webSocket:(SRWebSocket  *)webSocket  didFailWithError:(NSError  *)error{
    NetLog(@"连接失败");
    //[SVProgressHUD showErrorWithStatus:@"长连接连接失败"];
    self.isConnect  =  NO;
    self.connectType  =  WebSocketDisconnect;
    //判断网络环境
    if  (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus  ==  AFNetworkReachabilityStatusNotReachable){  //没有网络
        [self  noNetWorkStartTestingTimer];//开启网络检测定时器
    }else{  //有网络
         [self  reConnectServer];//连接失败就重连
    }
}
///接收消息
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
    NSString *jsonString = message;
    if ([message isKindOfClass:[NSData class]]) {
        jsonString = [[NSString alloc] initWithData:(NSData *)message encoding:NSUTF8StringEncoding];
    }
    NetLog(@"接收消息----   %@",jsonString);
    //[SVProgressHUD showInfoWithStatus:[NSString stringWithFormat:@"接收消息----   %@",jsonString]];
    if ([self.delegate  respondsToSelector:@selector(SocketManagerDidReceiveMessageWithString:)])  {
        [self.delegate  SocketManagerDidReceiveMessageWithString:jsonString];
    }
}
///关闭连接
-(void)webSocket:(SRWebSocket  *)webSocket  didCloseWithCode:(NSInteger)code  reason:(NSString  *)reason  wasClean:(BOOL)wasClean{
    NetLog(@"被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
    //[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"被关闭连接，code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean]];
    self.isConnect  =  NO;
    if (self.isActivelyClose) {
          self.connectType  =  WebSocketDefault;
          return;
    } else {
         self.connectType  =  WebSocketDisconnect;
    }
    
    [self  destoryHeartBeat];  //断开连接时销毁心跳
    
    //判断网络环境
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus  ==  AFNetworkReachabilityStatusNotReachable){  //没有网络
        [self  noNetWorkStartTestingTimer];//开启网络检测
    }else{  //有网络
        NetLog(@"关闭连接");
        _webSocket  =  nil;
        [self  reConnectServer];//连接失败就重连
    }
}
///ping
-(void)webSocket:(SRWebSocket  *)webSocket  didReceivePong:(NSData  *)pongData{
     NetLog(@"接受pong数据-->  %@",pongData);
}
#pragma  mark  -  NSTimer
//初始化心跳
- (void)initHeartBeat{
    //心跳没有被关闭
    if (self.heartBeatTimer) {
         return;
    }
    [self  destoryHeartBeat];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.heartBeatTimer = [NSTimer  timerWithTimeInterval:50  target:self  selector:@selector(senderheartBeat)  userInfo:nil  repeats:true];
        [[NSRunLoop  currentRunLoop] addTimer:self.heartBeatTimer  forMode:NSRunLoopCommonModes];
    });
}


//重新连接
- (void)reConnectServer{
    if(self.webSocket.readyState  ==  SR_OPEN){
        return;
    }

    if(self.reConnectTime  >  1024){    //重连10次  2^10  =  1024
        self.reConnectTime  =  0;
        return;
    }

    weak_block_self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,  (int64_t)(self.reConnectTime  *NSEC_PER_SEC)), dispatch_get_main_queue(),  ^{
           if(weakSelf.webSocket.readyState  ==  SR_OPEN  &&
              weakSelf.webSocket.readyState  ==  SR_CONNECTING)  {
                return;
           }
        
            //[SVProgressHUD showInfoWithStatus:@"重新连接长连接"];
            [weakSelf  connectServer];
            //     CTHLog(@"正在重连......");
            if(weakSelf.reConnectTime  ==  0){    //重连时间2的指数级增长
                weakSelf.reConnectTime  =  2;
            }else{
                weakSelf.reConnectTime  *=  2;
            }
    });
}
//发送心跳
- (void)senderheartBeat{
    //和服务端约定好发送什么作为心跳标识，尽可能的减小心跳包大小
    weak_block_self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if(weakSelf.webSocket.readyState  ==  SR_OPEN){
            NetLog(@"发送心跳");
            [weakSelf.webSocket send:@"h"];
        }
    });
}
//没有网络的时候开始定时  --  用于网络检测
- (void)noNetWorkStartTestingTimer{
    weak_block_self;
    dispatch_async(dispatch_get_main_queue(), ^{
        weakSelf.netWorkTestingTimer  =  [NSTimer  scheduledTimerWithTimeInterval:1.0  target:weakSelf  selector:@selector(noNetWorkStartTesting)  userInfo:nil  repeats:YES];
        [[NSRunLoop  currentRunLoop]  addTimer:weakSelf.netWorkTestingTimer  forMode:NSDefaultRunLoopMode];
    });
}
//定时检测网络
- (void)noNetWorkStartTesting{
    //有网络
    if(AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus  !=  AFNetworkReachabilityStatusNotReachable)
    {
        //关闭网络检测定时器
        [self  destoryNetWorkStartTesting];
        //开始重连
        [self  reConnectServer];
    }
}
//取消网络检测
-  (void)destoryNetWorkStartTesting{
    weak_block_self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if(weakSelf.netWorkTestingTimer)
        {
            [weakSelf.netWorkTestingTimer  invalidate];
            weakSelf.netWorkTestingTimer  =  nil;
        }
    });
}
//取消心跳
-  (void)destoryHeartBeat{
    weak_block_self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if(weakSelf.heartBeatTimer)
        {
            [weakSelf.heartBeatTimer  invalidate];
            weakSelf.heartBeatTimer  =  nil;
        }
    });
}
//关闭长连接
-  (void)WebSocketClose{
    self.isActivelyClose  =  YES;
    self.isConnect  =  NO;
    self.connectType  =  WebSocketDefault;
    if(self.webSocket)
    {
        [self.webSocket  close];
        _webSocket  =  nil;
    }

    //关闭心跳定时器
    [self  destoryHeartBeat];

    //关闭网络检测定时器
    [self  destoryNetWorkStartTesting];
}
//发送数据给服务器
-  (void)sendDataToServer:(NSString  *)data{
    //[self.sendDataArray  addObject:data];
    //[_webSocket  sendString:data  error:NULL];
    //没有网络
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus  ==  AFNetworkReachabilityStatusNotReachable)
    {
        // 开启网络检测定时器
        [self  noNetWorkStartTestingTimer];
    }
    else  //有网络
    {
        if (self.webSocket !=  nil)
        {
             //  只有长连接OPEN开启状态才能调  send  方法，不然会Crash
            if(self.webSocket.readyState  ==  SR_OPEN)
            {
//              if  (self.sendDataArray.count  >  0)
//              {
//               NSString  *data  =  self.sendDataArray[0];
                 [self.webSocket  send:data];  //发送数据
//               [self.sendDataArray  removeObjectAtIndex:0];
//               }
            }
            else  if (self.webSocket.readyState  ==  SR_CONNECTING)  //正在连接
            {
                NetLog(@"正在连接中，重连后会去自动同步数据");
            }
            else  if (self.webSocket.readyState  ==  SR_CLOSING  ||  self.webSocket.readyState  ==  SR_CLOSED)//断开连接
            {
                //调用  reConnectServer  方法重连,连接成功后  继续发送数据
                [self  reConnectServer];
            }
        }
        else
        {
            [self  connectServer];  //连接服务器
        }
    }
}
@end
